package com.innovation.ic.im.end.web.endpoint;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.innovation.ic.b1b.framework.util.StringUtils;
import com.innovation.ic.im.end.base.model.im_erp9.UserGroupMessage;
import com.innovation.ic.im.end.base.pojo.constant.Constants;
import com.innovation.ic.im.end.base.pojo.constant.RabbitMqExchangeMap;
import com.innovation.ic.im.end.base.pojo.constant.RedisStorage;
import com.innovation.ic.im.end.base.pojo.constant.UserLoginType;
import com.innovation.ic.im.end.base.handler.helper.HandlerHelper;
import com.innovation.ic.im.end.base.handler.im_erp9.WebSocketHandler;
import com.innovation.ic.im.end.base.thread.web.SaveUserLoginLogThread;
import com.innovation.ic.im.end.web.thread.SaveUserGroupMessageThread;
import com.innovation.ic.im.end.base.vo.im_erp9.LoginTypeVo;
import com.innovation.ic.im.end.base.vo.im_erp9.UserGroupMessageVo;
import com.innovation.ic.im.end.web.config.GetHttpSessionConfigurator;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;

@Data
@Component
@ServerEndpoint(value = "/ws/v1/userGroup/{userGroupId}/{username}", configurator = GetHttpSessionConfigurator.class)
public class UserGroupEndpoint extends AbstractEndpoint {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 与客户端的链接会话，需要通过它给客户端发送数据
     */
    public Session session;

    private Integer userGroupId;

    public String username;

    public String userNameStr;

    /**
     * 建立连接
     *
     * @param username
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("userGroupId") Integer userGroupId, @PathParam("username") String username, Session session, EndpointConfig config) {
        Map<String, Object> userProperties = session.getUserProperties();

        // 验证参数
        if (!StringUtils.validateParameter(username)) {
            logger.warn("参数username不能为空");
            return;
        }
        if (null == userGroupId) {
            logger.warn("参数userGroupId不能为空");
            return;
        }

        // 获取登录类型
        Integer loginType = getLoginType(userProperties);
        LoginTypeVo loginTypeVo = new LoginTypeVo(username, loginType);
        String usernameStr = JSONObject.toJSON(loginTypeVo).toString();

        // 把自己的信息加入到map当中去
        this.session = session;
        this.userGroupId = userGroupId;
        this.username = username;
        this.userNameStr = usernameStr;

        if (null == onlineUserGroupMap.get(userGroupId.toString())) {
            Set<UserGroupEndpoint> set = new HashSet<>();
            set.add(this);
            onlineUserGroupMap.put(userGroupId.toString(), set);
        } else {
            Set<UserGroupEndpoint> groupEndpoints = onlineUserGroupMap.get(userGroupId.toString());
            Boolean ifHave = Boolean.FALSE;
            for (UserGroupEndpoint userGroupEndpoint : groupEndpoints) {
                if (userGroupEndpoint.getUserNameStr().equals(userNameStr)) {
                    ifHave = true;
                    break;
                }
            }
            if (!ifHave) {
                onlineUserGroupMap.get(userGroupId.toString()).add(this);
            }
        }

        // 将username放入HttpSession中
//        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
//        httpSession.setAttribute("username", username);

        // redis存的键
        String redisKey = RedisStorage.ONLINE_USER_GROUP_MAP + ":" + userGroupId;
        WebSocketHandler webSocketHandler = HandlerHelper.getWebSocketHandler();
        // 获取Endpoint类中的onlineMap对象判断用户是否已登录
        Set<String> onlineUserGroupMap = webSocketHandler.getOnlineMap(redisKey);
        if (onlineUserGroupMap != null && onlineUserGroupMap.size() > 0) {
            Boolean result = Boolean.FALSE;
            for (String data : onlineUserGroupMap) {
                if (data.contains(userNameStr)) {
                    result = Boolean.TRUE;
                    break;
                }
            }
            if (!result) {
                // 记录用户登录信息
                JSONObject json = new JSONObject();
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(Constants.LOGGER, JSON.toJSONString(this.getLogger()));
                json.put(userNameStr, jsonObject.toString());
                webSocketHandler.putOnlineGroupMap(redisKey, json);
            }
        } else {
            // 记录用户登录信息
            JSONObject json = new JSONObject();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put(Constants.LOGGER, JSON.toJSONString(this.getLogger()));
            json.put(userNameStr, jsonObject.toString());
            webSocketHandler.putOnlineGroupMap(redisKey, json);
        }
        // 获取当前在线用户数量
        logger.info("session的id为【" + session.getId() + "】，参数userGroupId为【" + userGroupId + "】，" + "参数username为【" + username + "】，当前自定义群组在线人数【" + onlineUserGroupMap.size() + "】");

        // 进行记录用户登录信息
        String ipAddr = (String) userProperties.get(UserLoginType.IP_ADDR);
        logger.info("当前请求ip为" + ipAddr);
        SaveUserLoginLogThread saveUserLoginLogThread = new SaveUserLoginLogThread(username, userGroupId, UserLoginType.CUSTOM_USER_GROUP, ipAddr);
        threadPoolManager.execute(saveUserLoginLogThread);
    }

    /**
     * 报错
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 连接关闭
     */
    @OnClose
    public void onClose() {
        Iterator iterator = onlineUserGroupMap.keySet().iterator();
        while (iterator.hasNext()) {
            String groupId = (String) iterator.next();
            Set<UserGroupEndpoint> userGroupEndpointSet = onlineUserGroupMap.get(groupId);
            if (userGroupEndpointSet.size() > 0) {
                HashSet<UserGroupEndpoint> onlineUserSet = new HashSet<>();
                for (UserGroupEndpoint userGroupEndpoint : userGroupEndpointSet) {
                    if (userGroupEndpoint.getUserNameStr().equals(this.userNameStr)) {
                        // 用户账号account对应用户组groupId的登录对象从redis中删除
                        Long onlineAccountCount = delOnlineUserGroupMapFromRedis(userNameStr, groupId);
                        logger.info("用户【" + userGroupEndpoint.username + "】关闭了群组【" + userGroupEndpoint.userGroupId + "】，当前在线人数:【" + onlineAccountCount + "】");
                    } else {
                        onlineUserSet.add(userGroupEndpoint);
                    }
                }
                onlineUserGroupMap.remove(groupId);
                if (onlineUserSet.size() > 0) {
                    onlineUserGroupMap.put(groupId, onlineUserSet);
                }
            }
        }
    }

    /**
     * 收到客户端A的消息，将其发送给自定义群组中所有已经上线的成员。对于还没有上线的成员，则暂时将消息存储在数据库中
     * @param messageString 消息
     * @param session       会话
     */
    @OnMessage
    public void onMessage(String messageString, Session session) throws IOException {
        // 验证参数
        if (!StringUtils.validateParameter(messageString)) {
            logger.warn("参数messageString不能为空");
            return;
        }
        UserGroupMessageVo userGroupMessageVo = JSON.parseObject(messageString, UserGroupMessageVo.class);
        // type为-1时表示心跳，前端每隔5秒发送一次心跳，以免1分钟后websocket自动断开连接
        if (userGroupMessageVo.getType() == -1) {
            return;
        }
        if (!StringUtils.validateParameter(userGroupMessageVo.getContent())
                || !StringUtils.validateParameter(userGroupMessageVo.getFromUserAccount())
                || null == userGroupMessageVo.getUserGroupId()
                || null == userGroupMessageVo.getType()) {
            logger.warn("参数content、userGroupId、fromUserAccount和type不能为空");
            return;
        }
        logger.info("来自用户的消息【" + messageString + "】，客户端的session的id是【" + session.getId() + "】");

        // 将消息发送给自定义群组中每一个在线的用户，除了自己
        Set<UserGroupEndpoint> userGroupEndpointSet = onlineUserGroupMap.get(userGroupMessageVo.getUserGroupId().toString());
        Iterator<UserGroupEndpoint> userGroupEndpointIterator = userGroupEndpointSet.iterator();
        List<String> onlineAccountList = new ArrayList<>();
        while (userGroupEndpointIterator.hasNext()) {
            UserGroupEndpoint userGroupEndpoint = userGroupEndpointIterator.next();
            onlineAccountList.add(userGroupEndpoint.username);
        }

        // 保存自定义群组消息
        UserGroupMessage userGroupMessage = modelHandler.toUserGroupMessage(userGroupMessageVo);
        SaveUserGroupMessageThread saveUserGroupMessageThread = new SaveUserGroupMessageThread(userGroupMessage, userGroupMessageVo,
                onlineAccountList, rabbitMqParamConfig.getExchange().get(RabbitMqExchangeMap.CURRENT_EXCHANGE),
                onlineUserGroupMap, threadPoolManager);
        threadPoolManager.execute(saveUserGroupMessageThread);
    }

    /**
     * 用户账号account对应用户组groupId的登录对象从redis中删除
     *
     * @param username 用户名
     * @param groupId  用户组id
     * @return 返回当前自定义群组在线人数
     */
    private Long delOnlineUserGroupMapFromRedis(String username, String groupId) {
        WebSocketHandler webSocketHandler = HandlerHelper.getWebSocketHandler();
        String redisKey = RedisStorage.ONLINE_USER_GROUP_MAP + ":" + groupId;
        // 根据键值从redis中取onlineMap数据
        Set<String> redisData = webSocketHandler.getOnlineMap(redisKey);
        if (redisData != null && !redisData.isEmpty()) {
            Boolean delFlag = Boolean.FALSE;
            for (String data : redisData) {
                if (data.contains(username)) {
                    Long result = webSocketHandler.delOnlineMapValue(redisKey, data);
                    if (result.intValue() == 1) {
                        logger.info("用户:[{}]的自定义群组:[{}]登录信息已从redis中删除", username, groupId);
                        delFlag = Boolean.TRUE;
                        break;
                    }
                }
            }
            if (!delFlag) {
                logger.info("用户:[{}]的自定义群组:[{}]登录信息未从redis中查到,无法删除", username, groupId);
            }
        } else {
            logger.info("redis中不存在用户:[{}]的自定义群组:[{}]登录信息,不进行删除操作", username, groupId);
        }
        return webSocketHandler.getRedisKeySize(redisKey);
    }
}